/**
 * 
 */
package org.apache.james.imap.server;

import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.james.Constants;
import org.apache.james.imapserver.ImapConstants;
import org.apache.james.imapserver.ImapHandlerConfigurationData;
import org.apache.james.imapserver.ImapRequestLineReader;
import org.apache.james.imapserver.ImapResponse;
import org.apache.james.imapserver.ImapSession;
import org.apache.james.imapserver.ProtocolException;
import org.apache.james.imapserver.commands.ImapCommand;
import org.apache.james.imapserver.commands.ImapCommandFactory;
import org.apache.mina.common.IdleStatus;
import org.apache.mina.common.IoHandlerAdapter;
import org.apache.mina.common.IoSession;
import org.apache.mina.common.TransportType;
import org.apache.mina.transport.socket.nio.SocketSessionConfig;

/**
 * @author zsombor
 * 
 */
public class ImapServerHandler extends IoHandlerAdapter {

	private final ImapCommandFactory imapCommands = new ImapCommandFactory();

	private final String softwaretype = "JAMES/Mina " + ImapConstants.VERSION
			+ " Server " + Constants.SOFTWARE_VERSION;
    private static final String REQUEST_SYNTAX = "Protocol Error: Was expecting <tag SPACE command [arguments]>";

	ImapHandlerConfigurationData theConfig;

	public ImapServerHandler(ImapHandlerConfigurationData theConfig) {
		this.theConfig = theConfig;
		ImapServer.setupLog4jLogger(imapCommands);
	}

	@Override
	public void messageReceived(IoSession session, Object message)
			throws Exception {
		if (message instanceof String) {
			System.out.println("MESSAGE " + message);
			session.write(message);
		} else {
			if (message instanceof MinaImapMessage) {
				System.out.println("command:"+message);
				//session.write("received " + message);
				
				doProcessRequest((MinaImapMessage) message, session);
			}
		}
	}

	private void doProcessRequest(MinaImapMessage message, IoSession session) {
		MinaImapSession minaSession = MinaImapSession.get(session);
		doProcessRequest(message, minaSession.getImapResponseFormatter(), minaSession);
	}

	@Override
	public void sessionCreated(IoSession session) throws Exception {
		System.out.println("Session created...");

		MinaImapSession mis = new MinaImapSession(session, theConfig
				.getMailboxManagerProvider(), theConfig.getUsersRepository());

		if (session.getTransportType() == TransportType.SOCKET) {
			((SocketSessionConfig) session.getConfig())
					.setReceiveBufferSize(2048);
		}

		session.setIdleTime(IdleStatus.BOTH_IDLE, 30 * 60);

		mis.getImapResponseFormatter()
				.okResponse(
						null,
						softwaretype + " Server " + theConfig.getHelloName()
								+ " ready");
	}

	@Override
	public void exceptionCaught(IoSession session, Throwable cause)
			throws Exception {

		StringWriter sw = new StringWriter();
		cause.printStackTrace(new PrintWriter(sw));
		System.err.println("ERROR " + sw);

		MinaImapSession minaImapSession = MinaImapSession.get(session);

		minaImapSession.getImapResponseFormatter().badResponse(sw.toString());
	}

	private void doProcessRequest(ImapRequestLineReader request,
			ImapResponse response, ImapSession session) {
		String tag = null;
		String commandName = null;

		try {
			tag = request.tag();
		} catch (ProtocolException e) {
			response.badResponse(REQUEST_SYNTAX);
			return;
		}


		response.setTag(tag);
		try {
			commandName = request.atom();
		} catch (ProtocolException e) {
			response.commandError(REQUEST_SYNTAX);
			return;
		}

		ImapCommand command = imapCommands.getCommand(commandName);
		if (command == null) {
			response.commandError("Invalid command.");
			return;
		}

		if (!command.validForState(session.getState())) {
			response.commandFailed(command, "Command not valid in this state");
			return;
		}

		command.process(request, response, session);
	}

}
